
/*
 * @lc app=leetcode.cn id=889 lang=cpp
 *
 * [889] 根据前序和后序遍历构造二叉树
 *
 * https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/description/
 *
 * algorithms
 * Medium (67.73%)
 * Likes:    257
 * Dislikes: 0
 * Total Accepted:    26.5K
 * Total Submissions: 39.2K
 * Testcase Example:  '[1,2,4,5,3,6,7]\n[4,5,2,6,7,3,1]'
 *
 * 给定两个整数数组，preorder 和 postorder ，其中 preorder 是一个具有 无重复 值的二叉树的前序遍历，postorder
 * 是同一棵树的后序遍历，重构并返回二叉树。
 *
 * 如果存在多个答案，您可以返回其中 任何 一个。
 *
 *
 *
 * 示例 1：
 *
 *
 *
 *
 * 输入：preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
 * 输出：[1,2,3,4,5,6,7]
 *
 *
 * 示例 2:
 *
 *
 * 输入: preorder = [1], postorder = [1]
 * 输出: [1]
 *
 *
 *
 *
 * 提示：
 *
 *
 * 1 <= preorder.length <= 30
 * 1 <= preorder[i] <= preorder.length
 * preorder 中所有值都 不同
 * postorder.length == preorder.length
 * 1 <= postorder[i] <= postorder.length
 * postorder 中所有值都 不同
 * 保证 preorder 和 postorder 是同一棵二叉树的前序遍历和后序遍历
 *
 *
 */

// @lc code=start
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
private:
    unordered_map<int, int> hash;

public:
    TreeNode *constructFromPrePost(vector<int> &preorder, vector<int> &postorder) {
        int n = preorder.size();
        reverse(postorder.begin(), postorder.end());
        for (int i = 0; i < n; ++i) {
            hash[postorder[i]] = i;
        }
        return helper(preorder, postorder, 0, n - 1, 0, n - 1);
    }

    TreeNode *helper(vector<int> &preorder, vector<int> &postorder, int pre_left, int pre_right, int post_left, int post_right) {
        if (pre_left > pre_right) {
            return nullptr;
        }
        int root_pos = pre_left;
        TreeNode *root = new TreeNode(preorder[root_pos]);
        // 有子树
        if (pre_left + 1 <= pre_right) {
            // 只有单一子树
            if (preorder[pre_left + 1] == postorder[post_left + 1]) {
                root->left = helper(preorder, postorder, pre_left + 1, pre_right, post_left + 1, post_right);
                root->right = nullptr;
            }
            // 左右子树都有
            else {
                int left_size = post_right - hash[preorder[pre_left + 1]] + 1;
                root->left = helper(preorder, postorder, pre_left + 1, pre_left + left_size, post_right - left_size + 1, post_right);
                root->right = helper(preorder, postorder, pre_left + left_size + 1, pre_right, post_left + 1, post_right - left_size);
            }
        }
        return root;
    }
};
// @lc code=end
